using System;
using Iesi.Collections.Generic;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;
using Rhino.Commons.ForTesting;
using WineCellar.Data;
using WineCellar.Web;

namespace WineCellar.Tests.Model
{
	[TestFixture]
	public class ModelPersistanceFixture : DatabaseTestFixtureBase
	{
		[TestFixtureSetUp]
		public void TestFixtureSetUp()
		{
			logging log = logging.GetInstance(typeof (ModelPersistanceFixture));
		}

		[TestFixtureTearDown]
		public void TestFixtureTeardown()
		{			
		}

		[SetUp]
		public void Setup()
		{
            IntializeNHibernateAndIoC(PersistenceFramework.ActiveRecord, "../../windsor-AR.config",DatabaseEngine.MsSql2005Express,"wines_test",MappingInfo.FromAssemblyContaining<Wine>());            
			CurrentContext.CreateUnitOfWork();
		}

		[TearDown]
		public void TearDown()
		{										
		    CurrentContext.DisposeUnitOfWork();
            //hack: seems to be the only way to get rid of all tables. Must find cleaner way!
            new SchemaExport(CurrentContext.Configuration).Execute(true, true, true, true);
            new SchemaExport(CurrentContext.Configuration).Execute(true, true, true, true);
            new SchemaExport(CurrentContext.Configuration).Execute(true, true, true, true);
		}

		[Test]
		public void CanSaveUser()
		{
			User user = CreateUser("bart");
			Assert.AreEqual(null, user.UserId);
			Repository<User>.Save(user);

			UnitOfWork.Current.TransactionalFlush();
			UnitOfWork.CurrentSession.Evict(user);

			User fromDb = Repository<User>.Get(user.UserId);
			
			Assert.AreEqual("bart", fromDb.UserName);
			Assert.AreEqual(user.UserId, fromDb.UserId);
			
			Repository<User>.Delete(fromDb);
			UnitOfWork.Current.TransactionalFlush();
		}

		[Test]
		public void CanSaveRegion()
		{
			User user = GetUserPersistent("bart_region");
			Region region = CreateRegion(user);
			Repository<Region>.Save(region);

			UnitOfWork.Current.TransactionalFlush();
			UnitOfWork.CurrentSession.Evict(region);

			Region fromDb = Repository<Region>.Get(region.Id);
			Assert.AreEqual("Bordeaux", fromDb.Name);
			Assert.AreEqual(region.Id, fromDb.Id);
		}

		[Test]
		public void CanSaveRaisin()
		{
			User user = GetUserPersistent("bart_raisin");
			Raisin raisin = CreateRaisin(user);
			Repository<Raisin>.Save(raisin);

			UnitOfWork.Current.TransactionalFlush();
			UnitOfWork.CurrentSession.Evict(raisin);

			Raisin fromDb = Repository<Raisin>.Get(raisin.Id);
			Assert.AreEqual("Merlot", fromDb.Name);
			Assert.AreEqual(raisin.Id, fromDb.Id);
		}

		[Test]
		public void CanSaveCellar()
		{
			User user = GetUserPersistent("bart_cellar");
			Cellar cellar = CreateCellar(user);
			Repository<Cellar>.Save(cellar);

			UnitOfWork.Current.TransactionalFlush();
			UnitOfWork.CurrentSession.Evict(cellar);

			Cellar fromDb = Repository<Cellar>.Get(cellar.Id);
			Assert.AreEqual("Bart wijnkelder", fromDb.Name);
			Assert.AreEqual(cellar.Id, fromDb.Id);
		}

		[Test]
		public void CanSaveWine()
		{
			User user = GetUserPersistent("bart_wine");
			Region region = GetRegionPersistent("Bordeaux");
			ISet<Raisin> raisins = GetRaisinsPersistent(user);
			Wine wine = CreateWine(user, region, raisins);
			Repository<Wine>.Save(wine);

			UnitOfWork.Current.TransactionalFlush();
			UnitOfWork.CurrentSession.Evict(wine);

			Wine fromDb = Repository<Wine>.Get(wine.Id);
			Assert.AreEqual("Bart wijn", fromDb.Name);
			Assert.AreEqual(wine.Id, fromDb.Id);
			Assert.IsFalse(fromDb.Raisins.IsEmpty);
		}

		private User GetUserPersistent(string username)
		{
			User user = CreateUser(username);
			Repository<User>.Save(user);
			return user;
		}
		private Region GetRegionPersistent(string regionName)
		{
			User user = GetUserPersistent(regionName);
			Region region = CreateRegion(user);
			Repository<Region>.Save(region);
			return region;
		}
		private User CreateUser(string username)
		{
			User user = new User();
			user.ApplicationId = Guid.NewGuid();
			user.IsAnonymous = false;
			user.LastActivityDate = DateTime.Now;
			user.LoweredUserName = username.ToLower();
			user.UserName = username;
			return user;
		}
		private Region CreateRegion(User user)
		{
			Region region = new Region();
			region.AddedBy = user;
			region.DateAdded = DateTime.Now;
			region.Name = "Bordeaux";
			return region;
		}
		private Raisin CreateRaisin(User user)
		{
			Raisin raisin = new Raisin();
			raisin.Name = "Merlot";
			raisin.AddedBy = user;
			raisin.DateAdded = DateTime.Now;
			return raisin;
		}
		private ISet<Raisin> GetRaisinsPersistent(User user)
		{
			ISet<Raisin> raisins = new HashedSet<Raisin>();
			Raisin raisin1 = new Raisin();
			raisin1.Name = "Merlot";
			raisin1.AddedBy = user;
			raisin1.DateAdded = DateTime.Now;
			Repository<Raisin>.Save(raisin1);
			raisins.Add(raisin1);
			Raisin raisin2 = new Raisin();
			raisin2.Name = "Cabernet Sauvignon";
			raisin2.AddedBy = user;
			raisin2.DateAdded = DateTime.Now;
			Repository<Raisin>.Save(raisin2);
			raisins.Add(raisin2);
			return raisins;
		}
		private Cellar CreateCellar(User user)
		{
			Cellar cellar = new Cellar();
			cellar.DateAdded = DateTime.Now;
			cellar.Name = "Bart wijnkelder";
			cellar.User = user;
			return cellar;
		}
		private Wine CreateWine(User user, Region region, ISet<Raisin> raisins)
		{
			Wine wine = new Wine();
			wine.DateAdded = DateTime.Now;
			wine.Name = "Bart wijn";
			wine.AddedBy = user;
			wine.Region = region;
			wine.ColorType = "Red";
			wine.Appelation = "Medoc";
			wine.Producer = "Lafitte";
			wine.Raisins = raisins;
			return wine;
		}
	}
}
